#include "mysql.hpp"
#include "user.hxx"
#include "user-odb.hxx"

namespace bite_im
{
    // 数据库创建工厂
    class ODB_DB_Factory
    {
    public:
        static std::shared_ptr<odb::core::database> create(
            const std::string &user,
            const std::string &pswd,
            const std::string &host,
            const std::string &db,
            const std::string &cset,
            int port,
            int conn_pool_count)
        {

            // 创建连接池
            std::unique_ptr<odb::mysql::connection_pool_factory> cpf(
                new odb::mysql::connection_pool_factory(conn_pool_count, 0));



            auto res = std::make_shared<odb::mysql::database>(user, pswd, db, host, 
                port,"",cset, 0, std::move(cpf));


            return res;
        }
    };

    class UserTable
    {
    public:
        using ptr = std::shared_ptr<UserTable>;
        UserTable(const std::shared_ptr<odb::core::database> &db) : _db(db) {}

        bool Insert(const std::shared_ptr<User> &user)
        {
            try
            {
                odb::transaction trans(_db->begin()); // 获取并开启新事物
                _db->persist(*user);
                trans.commit();
            }
            catch (std::exception &e)
            {
                LOG_ERROR("新增用户失败{}，原因为:{}", user->nickname(), e.what());
                return false;
            }
            return true;
        }

        bool update(const std::shared_ptr<User> &user)
        {
            try
            {
                odb::transaction trans(_db->begin()); // 获取并开启新事物
                _db->update(*user);                  // 插入数据库，数据库自动判断是新增还是更新
                trans.commit();
            }
            catch (std::exception &e)
            {
                LOG_ERROR("更新用户失败{}，原因为:{}", user->nickname(), e.what());
                return false;
            }
            return true;
        }

        std::shared_ptr<User> select_by_nickname(const std::string &nickname)
        {
            std::shared_ptr<User> res;
            try
            {
                odb::transaction trans(_db->begin());
                typedef odb::query<User> query;
                typedef odb::result<User> result;
                // reset用于对shared_ptr的删除或重新替换
                res.reset(_db->query_one<User>(query::nickname == nickname));
                trans.commit();
            }
            catch (std::exception &e)
            {
                LOG_ERROR("通过昵称查询用户失败{}，原因为:{}", nickname, e.what());
            }
            return res;
        }

        std::shared_ptr<User> select_by_phone(const std::string &phone)
        {
            std::shared_ptr<User> res;
            try
            {
                odb::transaction trans(_db->begin());
                typedef odb::query<User> query;
                typedef odb::result<User> result;
                res.reset(_db->query_one<User>(query::phone == phone));
                trans.commit();
            }
            catch (std::exception &e)
            {
                LOG_ERROR("通过手机号查询用户失败 {}:{}！", phone, e.what());
            }
            return res;
        }

        std::shared_ptr<User> select_by_id(const std::string &user_id)
        {
            std::shared_ptr<User> res;
            try
            {
                odb::transaction trans(_db->begin());
                typedef odb::query<User> query;
                typedef odb::result<User> result;
                res.reset(_db->query_one<User>(query::user_id == user_id));
                trans.commit();
            }
            catch (std::exception &e)
            {
                LOG_ERROR("通过用户ID查询用户失败 {}:{}！", user_id, e.what());
            }
            return res;
        }

        std::vector<User> select_multi_users(const std::vector<std::string> &id_list)
        {
            // 数据库查询指令为
            // select * from user where id in('id1','id2',...)
            if (id_list.empty())
                return std::vector<User>();

            std::vector<User> res;
            try
            {
                odb::transaction trans(_db->begin());
                typedef odb::query<User> query;
                typedef odb::result<User> result;
                std::stringstream ss;
                ss << "user_id in (";
                for (const auto &id : id_list)
                {
                    ss << "'" << id << "',";
                }
                std::string condition = ss.str();
                condition.pop_back(); // 弹出末尾的逗号，
                condition += ")";
                result r(_db->query<User>(condition));
                for (result::iterator i(r.begin()); i != r.end(); ++i)
                {
                    res.push_back(*i);
                }
                trans.commit();
            }
            catch (std::exception &e)
            {
                LOG_ERROR("通过用户ID批量查询用户失败:{}！", e.what());
            }
            return res;
        }

    private:
        // odb对数据库的句柄，用于对数据库操作
        std::shared_ptr<odb::core::database> _db; // odb对数据库的句柄，用于对数据库操作
    };

}